# -*- coding: utf-8 -*-

#    OriginDB
#    Copyright (C) 2009  Jason Power <power.jg@gmail.com>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License along
#    with this program; if not, write to the Free Software Foundation, Inc.,
#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

from chemdb import dbHandle
from dbobject import DBObject

from reference import Reference
from compound import Compound

class Reaction(DBObject):
	"""This class holds the information of a chemical
	reaction. It holds info like temp catalysts...
	Also it has a list of catalysts kept in a different
	table.
	This class will auto populate itself
	"""

	def __init__(self, reactionId=-1):

		DBObject.__init__(self)

		self.id = reactionId

		#List of relation objects
		self._things['relations'] = []

		#List of catalyst object
		self._things['catalysts'] = []

		#List of compound object
		self._things['reactants'] = []
		self._things['products'] = []

		#Reference object
		self._things['reference'] = None

		#Integers
		self._things['temperature'] = None
		self._things['pressure'] = None
		self._things['time'] = None
		self._things['pH'] = None

		#Strings
		self._things['solvent'] = ''
		self._things['other'] = ''

		#bools
		self._things['liquid'] = False
		self._things['gas'] = False
		self._things['solid'] = False

	def _getItem(self, name):
		if self.id == -1:
			return self._things[name]
		if name=="relations":
			relationIds = dbHandle.getMany('id', 'relation', 'reaction_id', self.id)
			relations = [Relation(id) for id in relationIds]
			self._things['relations'] = relations
			return relations
		if name=="catalysts":
			catalystIds = dbHandle.getMany('id', 'catalyst', 'reaction_id', self.id)
			catalysts = [Catalyst(id) for id in catalystIds]
			for catalyst in catalysts:
				catalyst._things['reaction'] = self
			self._things['catalysts'] = catalysts
			return catalysts
		if name=="reactants":
			reactantIds = set(dbHandle.getMany('reactant_id', 'relation', 'reaction_id', self.id))
			reactants = [Compound(id) for id in reactantIds]
			self._things['reactants'] = reactants
			return reactants
		if name=="products":
			productIds = set(dbHandle.getMany('product_id', 'relation', 'reaction_id', self.id))
			products = [Compound(id) for id in productIds]
			self._things['products'] = products
			return products
		if name=="reference":
			refId = dbHandle.get('reference_id', 'reaction', 'id', self.id)
			ref = Reference(refId)
			self._things['reference'] = ref
			return ref
		if name=="temperature":
			temp = dbHandle.get('temperature', 'reaction', 'id', self.id)
			self._things['temperature'] = temp
			return temp
		if name=="time":
			time = dbHandle.get('time', 'reaction', 'id', self.id)
			self._things['time'] = time
			return time
		if name=="pressure":
			pressure = dbHandle.get('pressure', 'reaction', 'id', self.id)
			self._things['pressure'] = pressure
			return pressure
		if name=="pH":
			pH = dbHandle.get('pH', 'reaction', 'id', self.id)
			self._things['pH'] = pH
			return pH
		if name=="solvent":
			solvent = dbHandle.get('solvent', 'reaction', 'id', self.id)
			self._things['solvent'] = solvent
			return solvent
		if name=="liquid":
			state = dbHandle.get('liquid', 'reaction', 'id', self.id)
			if state==1:
				self._things['liquid'] = True
			else:
				self._things['liquid'] = False
			return self._things['liquid']
		if name=="gas":
			state = dbHandle.get('gas', 'reaction', 'id', self.id)
			if state==1:
				self._things['gas'] = True
			else:
				self._things['gas'] = False
			return self._things['gas']
		if name=="solid":
			state = dbHandle.get('solid', 'reaction', 'id', self.id)
			if state==1:
				self._things['solid'] = True
			else:
				self._things['solid'] = False
			return self._things['solid']
		if name=="other":
			other = dbHandle.get('other', 'reaction', 'id', self.id)
			self._things['other'] = other
			return other

	def insert(self):
		if self.id != -1:
			raise AttributeError, "Object already in DB"

		self.id = dbHandle.insertReaction()

		for i in self._needToUpdate:
			self.updateDB(i)
		self._needToUpdate = []

	def updateDB(self, name):
		if self.id ==-1:
			self._needToUpdate.append(name)
			return

		if name == 'catalysts':
			return		#TODO??
		elif name == 'reactants':
			return
		elif name == 'products':
			return
		elif name == 'reference':
			dbHandle.updateReaction(self.id, 'reference_id', self._things['reference'].id)
		elif name == 'liquid' or name == 'solid' or name == 'gas':
				dbHandle.updateReaction(self.id, name, 1 if self._things[name] else 0)
		elif name in self._things.keys():
			dbHandle.updateReaction(self.id, name, self._things[name])
		else:
			raise NameError, name

	def addCatalyst(self, catalyst):
		self.catalysts.append(catalyst)

		catalyst.reaction = self

		#todo insert catalyst???

	def addRelation(self, relation):
		self.relations.append(relation)

		relation.reaction = self

		#todo insert relation???


class Relation(DBObject):
	"""This class holds the information of a relationship
	   between two compounds.
	   This is also like compound and will auto populate itself.
	"""

	def __init__(self, relationId=-1):

		DBObject.__init__(self)

		self.id = relationId

		#Compound object
		self._things['reactant'] = None
		self._things['product'] = None

		#int (0-100)
		self._things['productYield'] = 0
		self._things['reactantPercent'] = 0

		#Reaction object
		self._things['reaction'] = None


	def _getItem(self, name):

		if name=="reactant":
			reactantId = dbHandle.get('reactant_id', 'relation', 'id', self.id)
			reactant = Compound(reactantId)
			self._things['reactant'] = reactant
			return reactant
		if name=="product":
			productId = dbHandle.get('product_id', 'relation', 'id', self.id)
			product = Compound(productId)
			self._things['product'] = product
			return product
		if name=="productYield":
			productYield = dbHandle.get("product_yield", 'relation', 'id', self.id)
			self._things['productYield'] = productYield
			return productYield
		if name=="reactantPercent":
			reactantPercent = dbHandle.get("reactant_percent", 'relation', 'id', self.id)
			self._things['reactantPercent'] = reactantPercent
			return reactantPercent
		if name=="reaction":
			reactionId = dbHandle.get('reaction_id', 'relation', 'id', self.id)
			reaction = Reaction(reactionId)
			self._things['reaction'] = reaction
			return reaction

	def insert(self):
		if self.id != -1:
			raise AttributeError, "Object already in DB"

		if "reactant" in self._needToUpdate and "product" in self._needToUpdate:
			self.id = dbHandle.insertRelation(self._things['reactant'].id, self._things['product'].id)
			self._needToUpdate.remove("reactant")
			self._needToUpdate.remove("product")
		else:
			raise AttributeError, "Need to add product and reactant before inserting", None

		for i in self._needToUpdate:
			self.updateDB(i)
		self._needToUpdate = []

	def updateDB(self, name):
		if self.id == -1:
			self._needToUpdate.append(name)
			return

		if name=="reactantPercent":
			dbHandle.updateRelation(self.id, 'reactant_percent', self._things[name])
		elif name=="productYield":
			dbHandle.updateRelation(self.id, 'product_yield', self._things[name])
		elif name in self._things.keys():
			dbHandle.updateRelation(self.id, name+"_id", self._things[name].id)
		else:
			raise NameError, name
			
	
	def delete(self):
		if self.id == -1:
			raise AttributeError, "Object not in DB"
			
		dbHandle.deleteRelation(self.id)


class Catalyst(DBObject):
	"""This class holds the information of a chemical
	reaction. It holds info like temp catalysts...
	Also it has a list of catalysts kept in a different
	table.
	This class will auto populate itself
	"""

	def __init__(self, catalystId=-1):

		DBObject.__init__(self)

		self.id = catalystId

		#string
		self._things['name'] = ""

		#reaction object
		self._things['reaction'] = None
		
		self._things['catalystId'] = -1

	def _getItem(self, name):
		if name=='name':
			name = dbHandle.get('name', 'catalyst', 'id', self.id)
			self._things['name'] = name
			return name
		if name=='reaction':
			reactionId = dbHandle.get('reaction_id', 'catalyst', 'id', self.id)
			reaction = Reaction(reactionId)
			self._things['reaction'] = reaction
			return reaction

	def insert(self):
		if self.id != -1:
			raise AttributeError, "Object already in DB"

		self.id = dbHandle.insertCatalyst()

		for i in self._needToUpdate:
			self.updateDB(i)
		self._needToUpdate = []

	def updateDB(self, name):
		if self.id == -1:
			self._needToUpdate.append(name)
			return

		if name == 'name':
			dbHandle.updateCatalyst(self.id, name, self._things[name])
		elif name == 'reaction':
			dbHandle.updateCatalyst(self.id, name+'_id', self._things[name].id)
		else:
			raise NameError, name


def searchForReactants(compound):

	reactants = dbHandle.searchReactants(compound.id)

	return [[Compound(pair[0]), Relation(pair[1])] for pair in reactants]

def searchForProducts(compound):

	products = dbHandle.searchProducts(compound.id)

	return [[Compound(pair[0]), Relation(pair[1])] for pair in products]


def searchForCatalyst(catalyst):
	query = {}
	if catalyst.name:
		query['name'] = catalyst.name

	ids = dbHandle.searchLike(query, 'catalyst')

	return [Catalyst(i[0]) for i in ids]